package com.huawei.hms.framework.network.restclient;

import com.huawei.hms.framework.network.restclient.ParameterBuilder.ClientConfig;
import com.huawei.hms.framework.network.restclient.annotate.Body;
import com.huawei.hms.framework.network.restclient.annotate.DELETE;
import com.huawei.hms.framework.network.restclient.annotate.Field;
import com.huawei.hms.framework.network.restclient.annotate.FieldMap;
import com.huawei.hms.framework.network.restclient.annotate.FormUrlEncoded;
import com.huawei.hms.framework.network.restclient.annotate.GET;
import com.huawei.hms.framework.network.restclient.annotate.HEAD;
import com.huawei.hms.framework.network.restclient.annotate.Header;
import com.huawei.hms.framework.network.restclient.annotate.HeaderMap;
import com.huawei.hms.framework.network.restclient.annotate.Headers;
import com.huawei.hms.framework.network.restclient.annotate.OnlyConnect;
import com.huawei.hms.framework.network.restclient.annotate.POST;
import com.huawei.hms.framework.network.restclient.annotate.PUT;
import com.huawei.hms.framework.network.restclient.annotate.Path;
import com.huawei.hms.framework.network.restclient.annotate.Query;
import com.huawei.hms.framework.network.restclient.annotate.QueryMap;
import com.huawei.hms.framework.network.restclient.annotate.Url;
import com.huawei.hms.framework.network.restclient.hwhttp.ClientConfiguration;
import com.huawei.hms.framework.network.restclient.hwhttp.HttpContants;
import com.huawei.hms.framework.network.restclient.hwhttp.Request;
import com.huawei.hms.framework.network.restclient.hwhttp.ResponseBody;
import com.huawei.hms.framework.network.restclient.hwhttp.url.HttpUrl;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URI;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable;

final class SubmitMethod<R, T> {
    static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
    static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);
    static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{([a-zA-Z][a-zA-Z0-9_-]*)\\}");
    private static final String TAG = "SubmitMethod";
    private final boolean bFormEncoded;
    private final HttpUrl baseUrl;
    private final String contentType;
    private final boolean hasBody;
    private final Headers headers;
    private boolean isOnlyConnect;
    private final String methodName;
    private final ParameterBuilder<?>[] parameterHandlers;
    private final String relativeUrl;
    private final Converter<ResponseBody, R> responseConverter;
    private final SubmitAdapter<R, T> submitAdapter;

    static final class Builder<R, T> {
        boolean bFormEncoded;
        boolean bGetBody;
        boolean bGetField;
        boolean bGetPath;
        boolean bGetQuery;
        boolean bGetUrl;
        String contentType;
        boolean hasBody;
        Headers headers;
        private boolean isOnlyConnect;
        Annotation[] mClassAnnotations;
        final Method method;
        final Annotation[] methodAnnotations;
        String methodName;
        final Annotation[][] parameterAnnotationsArray;
        ParameterBuilder<?>[] parameterHandlers;
        final Type[] parameterTypes;
        String relativeUrl;
        Set<String> relativeUrlParamNames;
        Converter<ResponseBody, R> responseConverter;
        Type responseType;
        final RestClient restClient;
        SubmitAdapter<R, T> submitAdapter;

        Builder(RestClient restClient, Method method, Class cls) {
            this.restClient = restClient;
            this.method = method;
            this.methodAnnotations = method.getAnnotations();
            this.parameterTypes = method.getGenericParameterTypes();
            this.parameterAnnotationsArray = method.getParameterAnnotations();
            this.mClassAnnotations = cls.getAnnotations();
        }

        public SubmitMethod build() {
            int length;
            int i = 0;
            this.submitAdapter = createSubmitAdapter(this.method);
            this.responseType = this.submitAdapter.responseType();
            this.responseConverter = findResponseConverter();
            for (Annotation parseClassAnnotation : this.mClassAnnotations) {
                parseClassAnnotation(parseClassAnnotation);
            }
            for (Annotation parseClassAnnotation2 : this.methodAnnotations) {
                parseMethodAnnotation(parseClassAnnotation2);
            }
            if (this.methodName == null) {
                throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).", new Object[0]);
            } else if (this.hasBody || !this.bFormEncoded) {
                length = this.parameterAnnotationsArray.length;
                this.parameterHandlers = new ParameterBuilder[length];
                while (i < length) {
                    Type type = this.parameterTypes[i];
                    if (Utils.hasUnresolvableType(type)) {
                        throw paramError(i, "Parameter type must not include a type variable or wildcard: " + type);
                    }
                    Annotation[] annotationArr = this.parameterAnnotationsArray[i];
                    if (annotationArr == null) {
                        throw paramError(i, "No RestClient annotation found.");
                    }
                    this.parameterHandlers[i] = parseParameter(i, type, annotationArr);
                    i++;
                }
                checkParam();
                return new SubmitMethod(this);
            } else {
                throw methodError("FormUrlEncoded can only be specified on HTTP methods with request body (e.g., @POST).", new Object[0]);
            }
        }

        private void parseClassAnnotation(Annotation annotation) {
            if (annotation instanceof Headers) {
                String[] value = ((Headers) annotation).value();
                if (value.length == 0) {
                    throw methodError("@Headers annotation is empty.", new Object[0]);
                }
                this.headers = parseHeaders(value);
            }
        }

        private void checkParam() {
            if (this.relativeUrl == null && !this.bGetUrl) {
                throw methodError("Missing either @%s URL or @Url parameter.", this.methodName);
            } else if (!this.bFormEncoded && !this.hasBody && this.bGetBody) {
                throw methodError("Non-body HTTP method cannot contain @Body.", new Object[0]);
            } else if (this.bFormEncoded && !this.bGetField) {
                throw methodError("Form-encoded method must contain at least one @Field.", new Object[0]);
            }
        }

        private SubmitAdapter<R, T> createSubmitAdapter(Method method) {
            Type genericReturnType = method.getGenericReturnType();
            if (Utils.hasUnresolvableType(genericReturnType)) {
                throw methodError("Method return type must not include a type variable or wildcard: " + genericReturnType, new Object[0]);
            } else if (genericReturnType == Void.TYPE) {
                throw methodError("Service methods cannot return void.", new Object[0]);
            } else {
                try {
                    return this.restClient.submitAdapter(genericReturnType, this.methodAnnotations);
                } catch (Throwable e) {
                    throw methodError(e, "Unable to create submit adapter for " + genericReturnType, new Object[0]);
                }
            }
        }

        private void parseMethodAnnotation(Annotation annotation) {
            if (annotation instanceof GET) {
                parseHttpMethodAndPath(HttpContants.HTTP_METHOD_GET, ((GET) annotation).value(), false);
            } else if (annotation instanceof DELETE) {
                parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
            } else if (annotation instanceof PUT) {
                parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
            } else if (annotation instanceof POST) {
                parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
            } else if (annotation instanceof HEAD) {
                parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
                if (!Void.class.equals(this.responseType)) {
                    throw methodError("HEAD method must use Void as response type.", new Object[0]);
                }
            } else if (annotation instanceof Headers) {
                String[] value = ((Headers) annotation).value();
                if (value.length == 0) {
                    throw methodError("@Headers annotation is empty.", new Object[0]);
                }
                this.headers = parseHeaders(value);
            } else if (annotation instanceof FormUrlEncoded) {
                this.bFormEncoded = true;
            } else if (annotation instanceof OnlyConnect) {
                this.isOnlyConnect = true;
            }
        }

        private void parseHttpMethodAndPath(String str, String str2, boolean z) {
            if (this.methodName != null) {
                throw methodError("Only one HTTP method is allowed. Found: %s and %s.", this.methodName, str);
            }
            this.methodName = str;
            this.hasBody = z;
            if (!str2.isEmpty()) {
                int indexOf = str2.indexOf(63);
                if (indexOf != -1 && indexOf < str2.length() - 1) {
                    if (SubmitMethod.PARAM_URL_REGEX.matcher(str2.substring(indexOf + 1)).find()) {
                        throw methodError("URL query string \"%s\" must not have replace block. For dynamic query parameters use @Query.", str2.substring(indexOf + 1));
                    }
                }
                this.relativeUrl = str2;
                this.relativeUrlParamNames = SubmitMethod.parsePathParameters(str2);
            }
        }

        private Headers parseHeaders(String[] strArr) {
            com.huawei.hms.framework.network.restclient.Headers.Builder builder;
            if (this.headers == null) {
                builder = new com.huawei.hms.framework.network.restclient.Headers.Builder();
            } else {
                builder = this.headers.newBuilder();
            }
            for (String str : strArr) {
                String str2;
                int indexOf = str2.indexOf(58);
                if (indexOf == -1 || indexOf == 0 || indexOf == str2.length() - 1) {
                    throw methodError("@Headers value must be in the form \"Name: Value\". Found: \"%s\"", str2);
                }
                String substring = str2.substring(0, indexOf);
                str2 = str2.substring(indexOf + 1).trim();
                if (HttpContants.KEY_CONTENT_TYPE.equalsIgnoreCase(substring)) {
                    this.contentType = str2;
                } else {
                    builder.add(substring, str2);
                }
            }
            return builder.build();
        }

        private ParameterBuilder<?> parseParameter(int i, Type type, Annotation[] annotationArr) {
            ParameterBuilder<?> parameterBuilder = null;
            for (Annotation parseParameterAnnotation : annotationArr) {
                ParameterBuilder<?> parseParameterAnnotation2 = parseParameterAnnotation(i, type, annotationArr, parseParameterAnnotation);
                if (parseParameterAnnotation2 != null) {
                    if (parameterBuilder != null) {
                        throw paramError(i, "Multiple RestClient annotations found, only one allowed.");
                    }
                    parameterBuilder = parseParameterAnnotation2;
                }
            }
            if (parameterBuilder != null) {
                return parameterBuilder;
            }
            throw paramError(i, "No RestClient annotation found.");
        }

        private ParameterBuilder<?> parseUrl(int i, Type type) {
            if (this.bGetUrl) {
                throw paramError(i, "Multiple @Url method annotations found.");
            } else if (this.bGetPath) {
                throw paramError(i, "@Path parameters may not be used with @Url.");
            } else if (this.bGetQuery) {
                throw paramError(i, "A @Url parameter must not come after a @Query");
            } else if (this.relativeUrl != null) {
                throw paramError(i, "@Url cannot be used with @%s " + this.methodName);
            } else {
                this.bGetUrl = true;
                if (type == String.class || type == URI.class || ((type instanceof Class) && "android.net.Uri".equals(((Class) type).getName()))) {
                    return new RelativeUrl();
                }
                throw paramError(i, "@Url must be String, java.net.URI, or android.net.Uri type.");
            }
        }

        private ParameterBuilder<?> parsePath(int i, Type type, Annotation[] annotationArr, Annotation annotation) {
            if (this.bGetQuery) {
                throw paramError(i, "A @Path parameter must not come after a @Query.");
            } else if (this.bGetUrl) {
                throw paramError(i, "@Path parameters may not be used with @Url.");
            } else if (this.relativeUrl == null) {
                throw paramError(i, "@Path can only be used with relative url on @" + this.methodName);
            } else {
                this.bGetPath = true;
                String value = ((Path) annotation).value();
                validatePathName(i, value);
                return new PathParam(value, this.restClient.stringConverter(type, annotationArr));
            }
        }

        private ParameterBuilder<?> parseQuery(int i, Type type, Annotation[] annotationArr, Annotation annotation) {
            String value = ((Query) annotation).value();
            Class rawType = Utils.getRawType(type);
            this.bGetQuery = true;
            if (Iterable.class.isAssignableFrom(rawType)) {
                if (type instanceof ParameterizedType) {
                    return new QueryParam(value, this.restClient.stringConverter(Utils.getParameterUpperBound(0, (ParameterizedType) type), annotationArr)).iterable();
                }
                throw paramError(i, rawType.getSimpleName() + " must include generic type (e.g., " + rawType.getSimpleName() + "<String>)");
            } else if (!rawType.isArray()) {
                return new QueryParam(value, this.restClient.stringConverter(type, annotationArr));
            } else {
                return new QueryParam(value, this.restClient.stringConverter(Utils.boxIfPrimitive(rawType.getComponentType()), annotationArr)).array();
            }
        }

        private ParameterBuilder<?> parseQueryMap(int i, Type type, Annotation[] annotationArr) {
            Class rawType = Utils.getRawType(type);
            if (Map.class.isAssignableFrom(rawType)) {
                Type supertype = Utils.getSupertype(type, rawType, Map.class);
                if (supertype instanceof ParameterizedType) {
                    ParameterizedType parameterizedType = (ParameterizedType) supertype;
                    Class parameterUpperBound = Utils.getParameterUpperBound(0, parameterizedType);
                    if (String.class != parameterUpperBound) {
                        throw paramError(i, "@QueryMap keys must be of type String: " + parameterUpperBound);
                    }
                    return new QueryMap(this.restClient.stringConverter(Utils.getParameterUpperBound(1, parameterizedType), annotationArr));
                }
                throw paramError(i, "Map must include generic types (e.g., Map<String, String>)");
            }
            throw paramError(i, "@QueryMap parameter type must be Map.");
        }

        private ParameterBuilder<?> parseHeader(int i, Type type, Annotation[] annotationArr, Annotation annotation) {
            String value = ((Header) annotation).value();
            Class rawType = Utils.getRawType(type);
            if (Iterable.class.isAssignableFrom(rawType)) {
                if (type instanceof ParameterizedType) {
                    return new Header(value, this.restClient.stringConverter(Utils.getParameterUpperBound(0, (ParameterizedType) type), annotationArr)).iterable();
                }
                throw paramError(i, rawType.getSimpleName() + " must include generic type (e.g., " + rawType.getSimpleName() + "<String>)");
            } else if (!rawType.isArray()) {
                return new Header(value, this.restClient.stringConverter(type, annotationArr));
            } else {
                return new Header(value, this.restClient.stringConverter(Utils.boxIfPrimitive(rawType.getComponentType()), annotationArr)).array();
            }
        }

        private ParameterBuilder<?> parseHeaderMap(int i, Type type, Annotation[] annotationArr) {
            Class rawType = Utils.getRawType(type);
            if (Map.class.isAssignableFrom(rawType)) {
                Type supertype = Utils.getSupertype(type, rawType, Map.class);
                if (supertype instanceof ParameterizedType) {
                    ParameterizedType parameterizedType = (ParameterizedType) supertype;
                    Class parameterUpperBound = Utils.getParameterUpperBound(0, parameterizedType);
                    if (String.class != parameterUpperBound) {
                        throw paramError(i, "@HeaderMap keys must be of type String: " + parameterUpperBound);
                    }
                    return new HeaderMap(this.restClient.stringConverter(Utils.getParameterUpperBound(1, parameterizedType), annotationArr));
                }
                throw paramError(i, "Map must include generic types (e.g., Map<String, String>)");
            }
            throw paramError(i, "@HeaderMap parameter type must be Map.");
        }

        private ParameterBuilder<?> parseField(int i, Type type, Annotation[] annotationArr, Annotation annotation) {
            if (this.bFormEncoded) {
                String value = ((Field) annotation).value();
                this.bGetField = true;
                Class rawType = Utils.getRawType(type);
                if (Iterable.class.isAssignableFrom(rawType)) {
                    if (type instanceof ParameterizedType) {
                        return new FieldParam(value, this.restClient.stringConverter(Utils.getParameterUpperBound(0, (ParameterizedType) type), annotationArr)).iterable();
                    }
                    throw paramError(i, rawType.getSimpleName() + " must include generic type (e.g., " + rawType.getSimpleName() + "<String>)");
                } else if (!rawType.isArray()) {
                    return new FieldParam(value, this.restClient.stringConverter(type, annotationArr));
                } else {
                    return new FieldParam(value, this.restClient.stringConverter(Utils.boxIfPrimitive(rawType.getComponentType()), annotationArr)).array();
                }
            }
            throw paramError(i, "@Field parameters can only be used with form encoding.");
        }

        private ParameterBuilder<?> parseFieldMap(int i, Type type, Annotation[] annotationArr) {
            if (this.bFormEncoded) {
                Class rawType = Utils.getRawType(type);
                if (Map.class.isAssignableFrom(rawType)) {
                    Type supertype = Utils.getSupertype(type, rawType, Map.class);
                    if (supertype instanceof ParameterizedType) {
                        ParameterizedType parameterizedType = (ParameterizedType) supertype;
                        Class parameterUpperBound = Utils.getParameterUpperBound(0, parameterizedType);
                        if (String.class != parameterUpperBound) {
                            throw paramError(i, "@FieldMap keys must be of type String: " + parameterUpperBound);
                        }
                        Converter stringConverter = this.restClient.stringConverter(Utils.getParameterUpperBound(1, parameterizedType), annotationArr);
                        this.bGetField = true;
                        return new FieldMap(stringConverter);
                    }
                    throw paramError(i, "Map must include generic types (e.g., Map<String, String>)");
                }
                throw paramError(i, "@FieldMap parameter type must be Map.");
            }
            throw paramError(i, "@FieldMap parameters can only be used with form encoding.");
        }

        private ParameterBuilder<?> parseBody(int i, Type type, Annotation[] annotationArr) {
            if (this.bFormEncoded) {
                throw paramError(i, "@Body parameters cannot be used with form or multi-part encoding.");
            } else if (this.bGetBody) {
                throw paramError(i, "Multiple @Body method annotations found.");
            } else {
                try {
                    Converter requestBodyConverter = this.restClient.requestBodyConverter(type, annotationArr, this.methodAnnotations);
                    this.bGetBody = true;
                    return new Body(requestBodyConverter);
                } catch (Throwable e) {
                    throw paramError(e, i, "Unable to create @Body converter for " + type);
                }
            }
        }

        private ParameterBuilder<?> parseClientConfig(int i, Type type) {
            if (type == ClientConfiguration.class) {
                return new ClientConfig();
            }
            throw paramError(i, "@ClientConfig must be com.huawei.hms.framework.network.rest.hwhttp.ClientConfiguration .");
        }

        private ParameterBuilder<?> parseParameterAnnotation(int i, Type type, Annotation[] annotationArr, Annotation annotation) {
            if (annotation instanceof Url) {
                return parseUrl(i, type);
            }
            if (annotation instanceof Path) {
                return parsePath(i, type, annotationArr, annotation);
            }
            if (annotation instanceof Query) {
                return parseQuery(i, type, annotationArr, annotation);
            }
            if (annotation instanceof QueryMap) {
                return parseQueryMap(i, type, annotationArr);
            }
            if (annotation instanceof Header) {
                return parseHeader(i, type, annotationArr, annotation);
            }
            if (annotation instanceof HeaderMap) {
                return parseHeaderMap(i, type, annotationArr);
            }
            if (annotation instanceof Field) {
                return parseField(i, type, annotationArr, annotation);
            }
            if (annotation instanceof FieldMap) {
                return parseFieldMap(i, type, annotationArr);
            }
            if (annotation instanceof Body) {
                return parseBody(i, type, annotationArr);
            }
            if (annotation instanceof com.huawei.hms.framework.network.restclient.annotate.ClientConfig) {
                return parseClientConfig(i, type);
            }
            return null;
        }

        private void validatePathName(int i, String str) {
            if (!SubmitMethod.PARAM_NAME_REGEX.matcher(str).matches()) {
                throw paramError(i, String.format("@Path parameter name must match %s. Found: %s", new Object[]{SubmitMethod.PARAM_URL_REGEX.pattern(), str}));
            } else if (!this.relativeUrlParamNames.contains(str)) {
                throw paramError(i, String.format("URL \"%s\" does not contain \"{%s}\".", new Object[]{this.relativeUrl, str}));
            }
        }

        private Converter<ResponseBody, R> findResponseConverter() {
            try {
                return this.restClient.responseBodyConverter(this.responseType, this.methodAnnotations);
            } catch (Throwable e) {
                throw methodError(e, "Unable to create converter for " + this.responseType, new Object[0]);
            }
        }

        private RuntimeException methodError(String str, Object... objArr) {
            return methodError(null, str, objArr);
        }

        private RuntimeException methodError(Throwable th, String str, Object... objArr) {
            return new IllegalArgumentException(String.format(str, objArr) + "\n    for method " + this.method.getDeclaringClass().getSimpleName() + "." + this.method.getName(), th);
        }

        private RuntimeException paramError(Throwable th, int i, String str) {
            return methodError(th, str + " (parameter #" + (i + 1) + ")", new Object[0]);
        }

        private RuntimeException paramError(int i, String str) {
            return methodError(str + " (parameter #" + (i + 1) + ")", new Object[0]);
        }
    }

    SubmitMethod(Builder<R, T> builder) {
        this.submitAdapter = builder.submitAdapter;
        this.baseUrl = builder.restClient.getBaseUrl();
        this.responseConverter = builder.responseConverter;
        this.methodName = builder.methodName;
        this.relativeUrl = builder.relativeUrl;
        this.headers = builder.headers;
        this.contentType = builder.contentType;
        this.hasBody = builder.hasBody;
        this.bFormEncoded = builder.bFormEncoded;
        this.parameterHandlers = builder.parameterHandlers;
        this.isOnlyConnect = builder.isOnlyConnect;
    }

    static Set<String> parsePathParameters(String str) {
        Matcher matcher = PARAM_URL_REGEX.matcher(str);
        Set<String> linkedHashSet = new LinkedHashSet();
        while (matcher.find()) {
            linkedHashSet.add(matcher.group(1));
        }
        return linkedHashSet;
    }

    Request toRequest(@Nullable Object... objArr) throws IOException {
        int length;
        RequestBuilder requestBuilder = new RequestBuilder(this.methodName, this.baseUrl, this.relativeUrl, this.headers, this.contentType, this.hasBody, this.bFormEncoded, this.isOnlyConnect);
        ParameterBuilder[] parameterBuilderArr = this.parameterHandlers;
        if (objArr != null) {
            length = objArr.length;
        } else {
            length = 0;
        }
        if (parameterBuilderArr == null) {
            throw new IllegalArgumentException("parameterHandlers is null");
        } else if (length != parameterBuilderArr.length) {
            throw new IllegalArgumentException("Argument count (" + length + ") doesn't match expected count (" + parameterBuilderArr.length + ")");
        } else {
            for (int i = 0; i < length; i++) {
                parameterBuilderArr[i].build(requestBuilder, objArr[i]);
            }
            return requestBuilder.build();
        }
    }

    R toResponse(ResponseBody responseBody) throws IOException {
        return this.responseConverter.convert(responseBody);
    }

    public T adapt(Submit<R> submit) {
        return this.submitAdapter.adapt(submit);
    }
}
